package com.gnkexy.springframework.context.supper;

import com.gnkexy.springframework.beans.BeansException;
import com.gnkexy.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.gnkexy.springframework.beans.factory.config.BeanFactoryPostProcessor;
import com.gnkexy.springframework.beans.factory.config.BeanPostProcessor;
import com.gnkexy.springframework.context.ApplicationEvent;
import com.gnkexy.springframework.context.ApplicationListener;
import com.gnkexy.springframework.context.ConfigurableApplicationContext;
import com.gnkexy.springframework.context.event.ApplicationEventMulticaster;
import com.gnkexy.springframework.context.event.ContextClosedEvent;
import com.gnkexy.springframework.context.event.ContextRefreshedEvent;
import com.gnkexy.springframework.context.event.SimpleApplicationEventMulticaster;
import com.gnkexy.springframework.core.io.DefaultResourceLoader;

import java.util.Collection;
import java.util.Map;

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    private ConfigurableListableBeanFactory beanFactory;

    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
    private ApplicationEventMulticaster applicationEventMulticaster;

    @Override
    public void refresh() throws BeansException {
        //创建beanFactory，加载beandifinition
        refreshBeanFactory();

        //获取beanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        //添加 ApplicationContextAwareProcessor，让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

        //在 Bean 实例化之前，执行 BeanFactoryPostProcessor
        invokeBeanFactoryPostProcess(beanFactory);

        //提前将BeanPostProcessor实例化到单例池中 ,BeanPostProcessor 需要提前于其他Bean对象实例化之前执行注册操作
        registerBeanPostProcessors(beanFactory);

        //提前实例化单例Bean对象
        beanFactory.preInstantiateSingletons();
        this.beanFactory = beanFactory;

        //初始化事件广播  new一个广播实现类放入单例池中
        initApplicationEventMultiucaster();

        //注册事件监听  向广播中的监听池中添加入我们配置中定义的监听器
        registerListeners();

        //发布一个刷新事件，广播将对所有的监听器进行匹配，匹配到的监听器返回，执行监听器方法
        finishRefresh();
    }
    private void initApplicationEventMultiucaster() {
        ConfigurableListableBeanFactory factory = getBeanFactory();
        applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        factory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME,applicationEventMulticaster);
    }
    private void registerListeners() throws BeansException {
        Collection<ApplicationListener> applicationListeners = beanFactory.getBeansOfType(ApplicationListener.class).values();
        for (ApplicationListener listener : applicationListeners) {
            applicationEventMulticaster.addApplicationListener(listener);
        }
    }
    private void finishRefresh() {
        publishEvent(new ContextRefreshedEvent(this));
    }
    @Override
    public void publishEvent(ApplicationEvent event) {
        applicationEventMulticaster.multicastEvent(event);
    }

    protected abstract void refreshBeanFactory();

    protected abstract ConfigurableListableBeanFactory getBeanFactory();

    private void invokeBeanFactoryPostProcess(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        Map<String, BeanFactoryPostProcessor> beans = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
        for (BeanFactoryPostProcessor beanFactoryPostProcessor : beans.values()) {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        }
    }

    private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        Map<String, BeanPostProcessor> beans = beanFactory.getBeansOfType(BeanPostProcessor.class);
//        for (BeanPostProcessor value : beans.values()) {
//            beanFactory.addBeanPostProcessor(value);
//        }
    }

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
        return beanFactory.getBeansOfType(type);
    }

    @Override
    public Object getBeanDifinitionNames() {
        return null;
    }

    @Override
    public Object getBean(String name) throws BeansException {
        return beanFactory.getBean(name);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return beanFactory.getBean(name, args);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) {
        return beanFactory.getBean(name, requiredType);
    }

    @Override
    public void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(this::close));
    }

    @Override
    public void close() {
        publishEvent(new ContextClosedEvent(this));

        getBeanFactory().destroySingletons();
    }
}
